/*	--- 责任链 Responsibility_Chain ---

#	使【多个对象】都有机会【处理请求】，从而避免【请求的发送者】和【接收者】之间的【耦合关系】。

将这些【对象】连成【一条链】，并沿着【这条链】传递【该请求】，直到有一个【对象】处理它为止。

==========================================================


【责任链模式】（Chain of Responsibility）是一种处理请求的模式，它让多个处理器都有机会处理该请求，直到其中某个处理成功为止。

【责任链模式 RResponsibility_Chain】把【多个处理器 Multi_Unit】串成【链 Chain】，然后让【请求 request】在【链 Chain】上传递： 


	     ┌─────────┐
	     │ Request │
	     └─────────┘
	          │
	┌ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ┐
	          ▼
	│  ┌─────────────┐  │
	   │ ProcessorA  │
	│  └─────────────┘  │
	          │
	│         ▼         │
	   ┌─────────────┐
	│  │ ProcessorB  │  │
	   └─────────────┘
	│         │         │
	          ▼
	│  ┌─────────────┐  │
	   │ ProcessorC  │
	│  └─────────────┘  │
	          │
	└ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ┘
	          │
	          ▼


在实际场景中，【财务审批】就是一个【责任链模式】。

假设【某个员工】需要【报销一笔费用】，【审核者】可以分为：

	· Manager：只能审核1000元以下的报销；
	· Director：只能审核10000元以下的报销；
	· CEO：可以审核任意额度。


用【责任链模式】设计此报销流程时，每个审核者只关心自己责任范围内的请求，并且处理它。

对于超出自己【责任范围】的，扔给【下一个审核者】处理，这样，将来继续【添加审核者】的时候，不用改动【现有逻辑】。

我们来看看【如何实现】【责任链模式】。

首先，我们要【抽象】出【请求对象】，它将在【责任链】上【(Request)传递】： */
public class Request {
	private String name;
	private BigDecimal amount;

	public Request(String name, BigDecimal amount) {
		this.name = name;
		this.amount = amount;
	}

	public String getName() {
		return name;
	}

	public BigDecimal getAmount() {
		return amount;
	}
}


/*
其次，我们要抽象出处理器： */
public interface Handler {
	
	Boolean process(Request request);
		// 返回Boolean.TRUE = 成功
		// 返回Boolean.FALSE = 拒绝
		// 返回null = 交给下一个处理
}


/*
并且做好约定：如果返回【Boolean.TRUE】，表示【处理成功】，如果【返回Boolean.FALSE】，表示【处理失败】（请求被拒绝），如果【返回null】，则交由【下一个Handler处理】。

然后，依次编写【ManagerHandler】、【DirectorHandler】和【CEOHandler】。

以【ManagerHandler】为例： */
public class Managerhandler implements Handler {
	public Boolean process(Request request) {
		// 如果超过1000元, 处理不了, 交给下一个Process_Unit
		if (request.getAmount().compareTo(BigDecimal.valueOf(1000)) > 0) {
			return null;
		}

		// 对Bob有【偏见】
		return !request.getName().equalsIgnoreCase("bob");
	}
}


/*
有了【不同的Handler】后，我们还要把【这些Handler】组合起来，变成一个【链】，并通过一个【统一入口处理】： */
public class HandlerChain {
	// 持有所有Handler
	private List<Handler> handlers = new ArrayList<>();

	public void add_Handler(Handler handler) {
		this.handlers.add(handler);
	}

	public boolean process(Request request) {
		// 依次调用每个Handler
		for (Handler handler : handlers) {

			Boolean r = handler.process(request);

			if (r != null) {
				// 如果返回 TRUE/FALSE, 处理结果
				System.out.println(request + " " + (r ? "Approved by" : "Denied by") + handler.getClass().getSimpleName());

				return r;
			}
		}

		throw new RuntimeException("Could not handle request: " + request);
	}
}


/*
现在，我们就可以在【客户端】组装出【责任链】，然后用【责任链】来【处理请求】： */

// 构造【责任链】
HandlerChain chain = new HandlerChain();
chain.add_Handler(new ManagerHandler());
chain.addHandler(new DirectorHandler());
chain.addHandler(new CEOHandler());

// 处理请求:
chain.process(new Request("Bob", new BigDecimal("123.45")));
chain.process(new Request("Alice", new BigDecimal("1234.56")));
chain.process(new Request("Bill", new BigDecimal("12345.67")));
chain.process(new Request("John", new BigDecimal("123456.78")));


/*
【责任链模式】本身很容易理解，需要注意的是，【Handler添加的顺序】很重要，如果【顺序不对】，【处理的结果】可能就【不是符合要求】的。

此外，【责任链模式】有很多变种。

有些【责任链的实现方式】是通过【某个Handler】手动调用【下一个Handler】来【传递Request】，例如： */
public class A_Handler implements Handler {
	private Handler next;

	public void process(Request request) {
		if (!canProcess(request)) {
			// 手动交给下一个Handler处理
			next.process(request);
		} else {
			// ...
		}
	}
}


/*
还有一些【责任链模式】，【每个Handler】都有机会【处理Request】，通常这种【责任链】被称为【拦截器】（Interceptor）或者【过滤器】（Filter），它的目的不是找到【某个Handler】处理掉【Request】，而是【每个Handler】都做一些工作，比如：

	· 记录日志；
	· 检查权限；
	· 准备相关资源；
	  ...


例如，【JavaEE的Servlet规范】定义的【Filter】就是一种【责任链模式】，它不但允许【每个Filter】都有机会【处理请求】，还允许【每个Filter】决定是否将【请求】“放行”给【下一个Filter】： */
public class AuitFilter implements Filter {
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,ServletException {

		log(req);

		if (check(req)) {
			// 放行
			chain.doFilter(req, resp);
		} else {
			// 拒绝
			sendError(resp);
		}
	}
}


/*
这种【责任链模式】不但允许【一个Filter】自行决定【处理ServletRequest和ServletResponse】，还可以【“伪造”ServletRequest和ServletResponse】以便让【下一个Filter处理】，能实现【非常复杂的功能】。


=============================================================


#	练习

使用【责任链模式】实现【审批】 */




/*============================================================

#	----- 责任链 ResponsibilityChain の 小结 ----- 


1. 【责任链模式】是一种把【多个处理器】组合【在一起】，【依次处理】请求的模式；

2. 【责任链模式的好处】是【添加新的处理器】或者【重新排列处理器】非常容易；

3. 【责任链模式】经常用在【拦截、预处理请求等】。



----------------

ResponsibilityChain 模版: 
	1. 定义【处理对象】 Request
	2. 定义【抽象处理单元】 Interface Handler
	3. 定义【实际处理单元】 class X_Handler implements Handler
	4. 定义【处理流水线】 HandlerChain 
*/
public class Request { // Request
	private String name;
	private BigDecimal amount;

	public Request(String name, BigDecimal amount) {
		this.name = name;
		this.amount = amount;
	}

	public String getName() {
		return name;
	}

	public BigDecimal getAmount() {
		return amount;
	}
}

// 抽象处理单元
public interface Handler {
	Boolean process(Request request);
}

// 实际处理单元
public class ManagerHandler implements Handler {
	public Boolean process(Request request) {
		if (request.getAmount.compareTo(BigDecimal.valueOf(1000)) > 0) {
			return null;
		}

		return ! request.getName().equalsIgnoreCase("bob");
	}
}

// 处理流水线
public class HandlerChain {
	private List<Handler> handlers = new ArrayList<>();

	public void addHandler(Handler handler) {
		this.handlers.add(handler); // List.add()
	}

	// HandlerChain.process(request), 流水线处理
	public boolean process(Request request) {
		for (Handler hndler : handlers) {
			Boolean r = handler.process(request);

			if (r != null) {
				System.out.println(request + " " + (r ? "Approved by " : "Denied by ") + handler.getClass().getSimpleName());
				return r;
			}

			throw new RuntimeException(handler + " could not handle request");

		}
	}
}

// Client调用
HandlerChain chain = new HandlerChain();
chain.addHandler(new ManagerHandler());
chain.addHandler(new DirectorHandler());
chain.addHandler(new CEOHandler());

// HandlerChain.process(request), 流水线处理
chain.process(new Request("Bob", new BigDecimal("123.45")));
chain.process(new Request("Alice", new BigDecimal("1234.56")));
chain.process(new Request("Bill", new BigDecimal("12345.67")));
chain.process(new Request("John", new BigDecimal("123456.78")));













